<template>
  <canvas ref="canvasRef"> </canvas>
</template>

<script setup>
import { ref, onMounted } from "vue";
const canvasRef = ref(null);
const ctxRef = ref(null);
const canvasDataRef = ref({
  width: 1000,
  height: 500,
  x: 0,
  y: 0,
  scale: 1,
  dx: 0,
  dy: 0,
  isDrag: false,
  lastX: 0,
  lastY: 0,
  dragShapeId: -1,
});
const shapeListRef = ref([
  { id: 1, x: 0, y: 0, width: 50, height: 50, fillStyle: "#f00" },
  { id: 2, x: 100, y: 100, width: 50, height: 50, fillStyle: "#0f0" },
]);

onMounted(() => {
  initCanvas();
});
const initCanvas = () => {
  const canvas = canvasRef.value;
  const canvasData = canvasDataRef.value;
  ctxRef.value = canvas.getContext("2d");
  canvas.width = canvasData.width;
  canvas.height = canvasData.height;
  initEvent(canvas);
  draw();
};
const initEvent = (canvas) => {
  canvas.addEventListener("mousedown", (e) => {
    const canvasData = canvasDataRef.value;
    const shapeList = shapeListRef.value;
    const canvas = canvasRef.value;
    const rect = canvas.getBoundingClientRect();
    canvasData.isDrag = true;
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    canvasData.lastX = e.clientX;
    canvasData.lastY = e.clientY;
    for (let i = 0; i < shapeList.length; i++) {
      var shape = shapeList[i];
      if (isPointInsideShape(x, y, getPosition(shape))) {
        canvasData.dragShapeId = shape.id;
        break;
      }
    }
  });

  canvas.addEventListener("mousemove", (e) => {
    const canvasData = canvasDataRef.value;
    const shapeList = shapeListRef.value;

    if (canvasData.isDrag) {
      const x = e.clientX;
      const y = e.clientY;
      canvasData.dx = (x - canvasData.lastX) * canvasData.scale;
      canvasData.dy = (y - canvasData.lastY) * canvasData.scale;
      canvasData.lastX = x;
      canvasData.lastY = y;

      if (canvasData.dragShapeId !== -1) {
        const shape =
          shapeList.find((item) => item.id === canvasData.dragShapeId) || {};
        shape.x = shape.x + canvasData.dx;
        shape.y = shape.y + canvasData.dy;
      } else {
        canvasData.x = canvasData.x + canvasData.dx;
        canvasData.y = canvasData.y + canvasData.dy;
      }

      draw();
    }
  });

  canvas.addEventListener("mouseup", () => {
    const canvasData = canvasDataRef.value;
    canvasData.isDrag = false;
    canvasData.dragShapeId = -1;
    canvasData.lastX = 0;
    canvasData.lastY = 0;
  });
  canvas.onmousewheel = function (e) {
    e.preventDefault();
    const canvasData = canvasDataRef.value;
    const delta = e.wheelDelta / 1800;
    let scale = canvasData.scale + delta;
    scale = Math.max(0.1, scale);
    scale = Math.min(scale, 4);
    canvasData.scale = scale;
    draw();
  };
};
const isPointInsideShape = (mouseX, mouseY, shape) => {
  return (
    mouseX > shape.x &&
    mouseX < shape.x + shape.width &&
    mouseY > shape.y &&
    mouseY < shape.y + shape.height
  );
};
const draw = () => {
  const ctx = ctxRef.value;
  const canvasData = canvasDataRef.value;
  const canvasWidth = ctx.canvas.width;
  const canvasHeight = ctx.canvas.height;
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);
  // 设置网格
  drawLine(10 * canvasData.scale);
  drawShape();
};
const drawLine = (girdSize) => {
  const ctx = ctxRef.value;
  ctx.beginPath();
  const canvasWidth = ctx.canvas.width;
  const canvasHeight = ctx.canvas.height;
  const xLineTotals = Math.floor(canvasHeight / girdSize);
  const yLineTotals = Math.floor(canvasWidth / girdSize);
  for (let i = 1; i < xLineTotals; i++) {
    ctx.moveTo(0, +girdSize * i);
    ctx.lineTo(canvasWidth, girdSize * i);
  }
  for (let j = 1; j < yLineTotals; j++) {
    ctx.moveTo(girdSize * j, 0);
    ctx.lineTo(girdSize * j, canvasHeight);
  }
  ctx.setLineDash([0.5, 1]);
  ctx.strokeStyle = "#ccc";
  ctx.lineWidth = 1;
  ctx.stroke();
};
const drawShape = () => {
  const ctx = ctxRef.value;
  const shapeList = shapeListRef.value;
  shapeList.forEach((item) => {
    const { x, y, width, height } = getPosition(item);
    ctx.beginPath();
    ctx.fillStyle = item.fillStyle;
    ctx.rect(x, y, width, height);
    ctx.fill();
  });
};

const getPosition = ({ x = 0, y = 0, width = 0, height = 0 }) => {
  const canvasData = canvasDataRef.value;
  return {
    x: (canvasData.x + x) * canvasData.scale,
    y: (canvasData.y + y) * canvasData.scale,
    width: width * canvasData.scale,
    height: height * canvasData.scale,
  };
};
</script>

<style scoped>
canvas {
  background-color: #fff;
}
</style>
